package cn.tedu._06springaop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
public class LogAspect {
    /**
     * Before注解：前置通知，调用目标方法之前执行
     * @Pointcut注解：定义切入点表达式的方法
     */

    @Pointcut("execution(public int cn.tedu._06springaop.aop.CalculatorImpl.*(..))")
    public void pointCut() {
    }
//    @Before("execution(public int cn.tedu._06springaop.aop.CalculatorImpl.*(..))")
//    public void beforeMethod(JoinPoint joinPoint) {
//        String name = joinPoint.getSignature().getName();
//        String args = Arrays.toString(joinPoint.getArgs());
//        System.out.println("[前置通知]"+name + "方法开始执行，参数为" + args);
//    }
//    @After("execution(public int cn.tedu._06springaop.aop.CalculatorImpl.*(..))")
//    public void afterMethod(JoinPoint joinPoint){
//        String name = joinPoint.getSignature().getName();
//        System.out.println("[后置通知]"+name + "方法执行结束");
//    }
//
//    /**
//     * @AfterReturning注解
//     * 1.目标方法正常结束后执行，如果是异常结束，则不执行
//     * 2.可以获取到，目标方法的返回值
//     * 参数说明：
//     * 1.value参数：切入点表达式
//     * 2.returning参数：用户接收目标方法的返回值
//     * @param joinPoint
//     * @param result
//     */
//
//    @AfterReturning(value = "pointCut()", returning = "result")
//    public void afterReturning(JoinPoint joinPoint, Object result){
//        String name = joinPoint.getSignature().getName();
//        System.out.println("[返回通知]"+name+"方法正常返回，结果为"+result);
//    }
//    /**
//     * 异常通知
//     * @AfterThrowing注解
//     * 1.异常通知，目标方法抛出异常时执行，如果正常结束则不执行
//     * 2。可以获取到异常对象，并执行异常处理逻辑
//     */
//    @AfterThrowing(value = "pointCut()", throwing = "ex")
//    public void afterThrowingMethod(JoinPoint joinPoint, Exception ex){
//        String name = joinPoint.getSignature().getName();
//        System.out.println("[异常通知]"+name+"方法出现异常，异常为"+ex.getMessage());
//    }
    /**
     * @Around注解环绕通知
     * 等价于@Before+@After+@AfterReturning+@AfterThrowing
     * 2.通常被try...catch...finally语句包围
     */
    @Around("pointCut()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint){
        Object result = null;
        /*
        try{
            1.前置通知
            2.执行目标方法； joinPoint.proceed()
            3.返回通知
            }catch(){
            4.异常通知
            }finally{
            5.后置通知
            }

         */
        try{
            System.out.println("[环绕通知]"+"前置通知方法执行开始");
            result = joinPoint.proceed();
            System.out.println("[环绕通知]"+"返回通知");
        }catch(Throwable throwable){
            System.out.println("环绕通知异常[异常通知]");
            throw new RuntimeException(throwable);
        }finally {
            System.out.println("[环绕通知]"+"后置通知方法执行结束");
        }
        return result;
    }
}
